package com.project.web.wechat.controller.common;

import com.google.gson.Gson;
import com.project.web.config.WxCorp.WxCpConfiguration;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

/**
 * 企业微信回调控制器
 *
 * @author wyy
 * @date 2020-06-24
 */
@ApiIgnore
@RestController("workWeChatNotifyController")
@RequestMapping("/weChat/anon/workWeChat/portal")
public class WorkWeChatNotifyController extends BaseController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 企业微信回调函数验证
     *
     * @param corpId        企业id
     * @param agentId       应用ID
     * @param msg_signature 企业微信加密签名
     * @param timestamp     时间戳
     * @param nonce         随机数
     * @param echostr       加密的字符串
     * @return
     */
    @GetMapping("/{corpId}/{agentId}")
    public String authGet(@PathVariable String corpId, @PathVariable String agentId, String msg_signature, String timestamp, String nonce, String echostr) {
        this.logger.info("\n接收到来自微信服务器的认证消息：signature = [{}], timestamp = [{}], nonce = [{}], echostr = [{}]",
                msg_signature, timestamp, nonce, echostr);

        if (StringUtils.isAnyBlank(msg_signature, timestamp, nonce, echostr)) {
            throw new IllegalArgumentException("请求参数非法，请核实!");
        }

        final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId, agentId);
        if (wxCpService == null) {
            throw new IllegalArgumentException(String.format("未找到对应agentId=[%d]的配置，请核实！", agentId));
        }

        if (wxCpService.checkSignature(msg_signature, timestamp, nonce, echostr)) {
            String decrypt = new WxCpCryptUtil(wxCpService.getWxCpConfigStorage()).decrypt(echostr);
            log.info("\r\n ************ 企业微信回掉验证返回信息：{}", decrypt);
            return decrypt;
        }
        return "非法请求";
    }

    /**
     * 企业微信回调事件通知
     *
     * @param corpId      企业ID
     * @param agentId     应用ID
     * @param requestBody 事件内容
     * @param signature   企业微信加密签名
     * @param timestamp   时间戳
     * @param nonce       随机数
     * @return
     */
    @PostMapping("/{corpId}/{agentId}")
    public String post(@PathVariable String corpId,
                       @PathVariable String agentId,
                       @RequestBody String requestBody,
                       @RequestParam("msg_signature") String signature,
                       @RequestParam("timestamp") String timestamp,
                       @RequestParam("nonce") String nonce) {
        this.logger.info("\r\n ***********企业微信回掉数据：[signature=[{}], timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                signature, timestamp, nonce, requestBody);

        final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId, agentId);
        WxCpXmlMessage inMessage = WxCpXmlMessage.fromEncryptedXml(requestBody, wxCpService.getWxCpConfigStorage(),
                timestamp, nonce, signature);
        this.logger.debug("\r\n *********消息解密后：\n{} ", new Gson().toJson(inMessage));
        WxCpXmlOutMessage outMessage = this.route(corpId, agentId, inMessage);
        if (outMessage == null) {
            return "";
        }

        String out = outMessage.toEncryptedXml(wxCpService.getWxCpConfigStorage());
        this.logger.debug("\n组装回复信息：{}", out);
        return out;
    }

    /**
     * 获取对应企业下应用的路由
     *
     * @param corpId  企业ID
     * @param agentId
     * @param message
     * @return
     */
    private WxCpXmlOutMessage route(String corpId, String agentId, WxCpXmlMessage message) {
        try {
            return WxCpConfiguration.getCpMsgRouter(corpId, agentId).route(message);
        } catch (Exception e) {
            this.logger.error(e.getMessage(), e);
        }
        return null;
    }
}
